package ckeditor;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

/**
 * Servlet implementation class CKEditorUploadServlet
 */
public class CKEditorUploadServlet extends HttpServlet {  
    private static String baseDir;// CKEditor的根目錄  
    private static boolean debug = false;// 是否debug模式  
    private static boolean enabled = false;// 是否開啟CKEditor上傳  
    private static Hashtable allowedExtensions;// 允許的上傳文件擴展名  
    private static Hashtable deniedExtensions;// 阻止的上傳文件擴展名  
    private static SimpleDateFormat dirFormatter;// 目錄命名格式:yyyyMM  
    private static SimpleDateFormat fileFormatter;// 文件命名格式:yyyyMMddHHmmssSSS  
    /** 
     * Servlet初始化方法 
     */  
    public void init() throws ServletException {  
        // 從web.xml中讀取debug模式  
        debug = (new Boolean(getInitParameter("debug"))).booleanValue();  
        if (debug)  
            System.out.println("\r\n---- SimpleUploaderServlet initialization started ----");  
        // 格式化目錄和文件命名方式  
        dirFormatter = new SimpleDateFormat("yyyyMM");  
        fileFormatter = new SimpleDateFormat("yyyyMMddHHmmssSSS");  
        // 從web.xml中獲取根目錄名稱  
        baseDir = getInitParameter("baseDir");  
        // 從web.xml中獲取是否可以進行文件上傳  
        enabled = (new Boolean(getInitParameter("enabled"))).booleanValue();  
        if (baseDir == null)  
            baseDir = "/UserFiles/";  
        String realBaseDir = getServletContext().getRealPath(baseDir);  
        File baseFile = new File(realBaseDir);  
        if (!baseFile.exists()) {  
            baseFile.mkdirs();  
        }  
        // 實例化允許的擴展名和阻止的擴展名  
        allowedExtensions = new Hashtable(3);  
        deniedExtensions = new Hashtable(3);  
        // 從web.xml中讀取配置信息  
        //allowedExtensions.put("File",stringToArrayList(getInitParameter("AllowedExtensionsFile")));  
        //deniedExtensions.put("File",stringToArrayList(getInitParameter("DeniedExtensionsFile")));  
        //allowedExtensions.put("Image",stringToArrayList(getInitParameter("AllowedExtensionsImage")));  
        //deniedExtensions.put("Image",stringToArrayList(getInitParameter("DeniedExtensionsImage")));  
        if (debug)  
            System.out.println("---- SimpleUploaderServlet initialization completed ----\r\n");  
    }  
    public void doGet(HttpServletRequest request, HttpServletResponse response)  
            throws ServletException, IOException {  
        doPost(request, response);  
    }  
    public void doPost(HttpServletRequest request, HttpServletResponse response)  
            throws ServletException, IOException {  
        if (debug)  
            System.out.println("--- BEGIN DOPOST ---");  
        response.setContentType("text/html; charset=UTF-8");  
        response.setHeader("Cache-Control", "no-cache");  
        PrintWriter out = response.getWriter();  
        // 從請求參數中獲取上傳文件的類型：File/Image/Flash  
        String typeStr = request.getParameter("Type");  
        if (typeStr == null) {  
            typeStr = "File";  
        }  
        if (debug)  
            System.out.println(typeStr);  
        // 實例化dNow對象，獲取當前時間  
        Date dNow = new Date();  
        // 設定上傳文件路徑  
        String currentPath = baseDir + typeStr + "/" + dirFormatter.format(dNow);  
        // 獲得web應用的上傳路徑  
        String currentDirPath = getServletContext().getRealPath(currentPath);  
        // 判斷文件夾是否存在，不存在則創建  
        File dirTest = new File(currentDirPath);  
        if (!dirTest.exists()) {  
            dirTest.mkdirs();  
        }  
        // 將路徑前加上web應用名  
        currentPath = request.getContextPath() + currentPath;  
        if (debug)  
            System.out.println(currentDirPath);  
        // 文件名和文件真實路徑  
        String newName = "";  
        String fileUrl = "";  
        if (enabled) {  
            // 使用Apache Common組件中的fileupload進行文件上傳  
            FileItemFactory factory = new DiskFileItemFactory();  
            ServletFileUpload upload = new ServletFileUpload(factory);  
            try {  
                List items = upload.parseRequest(request);  
                Map fields = new HashMap();  
                Iterator iter = items.iterator();  
                while (iter.hasNext()) {  
                    FileItem item = (FileItem) iter.next();  
                    if (item.isFormField())  
                        fields.put(item.getFieldName(), item.getString());  
                    else  
                        fields.put(item.getFieldName(), item);  
                }  
                // CEKditor中file域的name值是upload  
                FileItem uplFile = (FileItem) fields.get("upload");  
                // 獲取文件名並做處理  
                String fileNameLong = uplFile.getName();  
                fileNameLong = fileNameLong.replace('\\','/');  
                String[] pathParts = fileNameLong.split("/");  
                String fileName = pathParts[pathParts.length - 1];  
                // 獲取文件擴展名  
                String ext = getExtension(fileName);  
                // 設置上傳文件名  
                fileName = fileFormatter.format(dNow) + "." + ext;  
                // 獲取文件名(無擴展名)  
                String nameWithoutExt = getNameWithoutExtension(fileName);  
                File pathToSave = new File(currentDirPath, fileName);  
                fileUrl = currentPath + "/" + fileName;  
                if (true) {  
                    int counter = 1;  
                    while (pathToSave.exists()) {  
                        newName = nameWithoutExt + "_" + counter + "." + ext;  
                        fileUrl = currentPath + "/" + newName;  
                        pathToSave = new File(currentDirPath, newName);  
                        counter++;  
                    }  
                    uplFile.write(pathToSave);  
                } else if(debug) {
                	System.out.println("無效的文件類型： " + ext);  
                }  
            } catch (Exception ex) {  
                if (debug)  
                    ex.printStackTrace();  
            }  
        } else {  
            if (debug)  
                System.out.println("未開啟CKEditor上傳功能");  
        }  
        // CKEditorFuncNum是回調時顯示的位置，這個參數必須有  
        String callback = request.getParameter("CKEditorFuncNum");  
        out.println("<script type=\"text/javascript\">");  
        out.println("window.parent.CKEDITOR.tools.callFunction(" + callback  
                + ",'" + fileUrl + "',''" + ")");  
        out.println("</script>");  
        out.flush();  
        out.close();  
        if (debug)  
            System.out.println("--- END DOPOST ---");  
    }  
    /** 
     * 獲取文件名的方法 
     */  
    private static String getNameWithoutExtension(String fileName) {  
        return fileName.substring(0, fileName.lastIndexOf("."));  
    }  
    /** 
     * 獲取擴展名的方法 
     */  
    private String getExtension(String fileName) {  
        return fileName.substring(fileName.lastIndexOf(".") + 1);  
    }  
    /** 
     * 字符串像ArrayList轉化的方法 
     */  
    private ArrayList stringToArrayList(String str) {  
        if (debug)  
            System.out.println(str);  
        String[] strArr = str.split("\\|");  
        ArrayList tmp = new ArrayList();  
        if (str.length() > 0) {  
            for (int i = 0; i < strArr.length; ++i) {  
                if (debug)  
                    System.out.println(i + " - " + strArr[i]);  
                tmp.add(strArr[i].toLowerCase());  
            }  
        }  
        return tmp;  
    }  
    /** 
     * 判斷擴展名是否允許的方法 
     */  
    private boolean extIsAllowed(String fileType, String ext) {  
        ext = ext.toLowerCase();  
        ArrayList allowList = (ArrayList) allowedExtensions.get(fileType);  
        ArrayList denyList = (ArrayList) deniedExtensions.get(fileType);  
        if (allowList.size() == 0) {  
            if (denyList.contains(ext)) {  
                return false;  
            } else {  
                return true;  
            }  
        }  
        if (denyList.size() == 0) {  
            if (allowList.contains(ext)) {  
                return true;  
            } else {  
                return false;  
            }  
        }  
        return false;  
    }  
}  